﻿#include "TouchInjector.h"
#include <QList>
#include <QTouchEvent>
#include <QElapsedTimer>
#include <Windows.h>
#include <QDebug>

typedef BOOL (WINAPI *pInitializeTouchInjection)(UINT32, DWORD);
typedef BOOL (WINAPI *pInjectTouchInput)(UINT32, const POINTER_TOUCH_INFO*);

static pInitializeTouchInjection _InitializeTouchInjection = nullptr;
static pInjectTouchInput _InjectTouchInput = nullptr;

TouchInjector::TouchInjector(int maxPoints)
    : m_orientation(Qt::LandscapeOrientation)
{
    HMODULE user32 = LoadLibraryW(L"user32.dll");
    if (user32 && !_InitializeTouchInjection) {
        _InitializeTouchInjection = (pInitializeTouchInjection)GetProcAddress(user32, "InitializeTouchInjection");
        _InjectTouchInput = (pInjectTouchInput)GetProcAddress(user32, "InjectTouchInput");
    }

    if (_InitializeTouchInjection) {
        _InitializeTouchInjection(maxPoints, TOUCH_FEEDBACK_DEFAULT);
    } else {
        qWarning("Touch injection API not available on this system.");
    }
}

void TouchInjector::setRect(const QRect &rect)
{
    m_rect = rect;
}

void TouchInjector::setOrientation(const Qt::ScreenOrientation &orientation)
{
    m_orientation = orientation;
}

void TouchInjector::inject(const QList<TouchPoint>& points, WorkMode workMode)
{
    switch (workMode) {
    case Touch:
        handleTouch(points);
        break;
    case Mouse:
        handleMouse(points);
        break;
    default:
        break;
    }
}

QPoint TouchInjector::mapToScreen(const QPoint &pt) const
{
    int w = m_rect.width();
    int h = m_rect.height();

    switch (m_orientation) {
    case Qt::LandscapeOrientation:  // 横向（默认方向）
        return pt;

    case Qt::InvertedLandscapeOrientation:  // 横向翻转（180°）
        return QPoint(w - pt.x(), h - pt.y());

    case Qt::PortraitOrientation:  // 纵向（顺时针90°）
        // 原点在左下角，x 变为 y，y 变为宽 - x
        return QPoint(w - pt.y(), pt.x());

    case Qt::InvertedPortraitOrientation:  // 纵向翻转（逆时针90°）
        // 原点在右上角，x 变为 y，y 变为高 - x
        return QPoint(pt.y(), h - pt.x());

    default:
        return pt;
    }
}

void TouchInjector::handleTouch(const QList<TouchPoint> &points)
{
    if (!_InjectTouchInput) return;

    std::vector<POINTER_TOUCH_INFO> touchList;
    touchList.reserve(points.size());

    for (const TouchPoint& point : points) {
        if (!point.isValid()) continue;


        POINTER_TOUCH_INFO contact;
        memset(&contact, 0, sizeof(contact));

        // int x = m_rect.left() + point.x();
        // int y = m_rect.top() + point.y();
        QPoint mapped = mapToScreen(QPoint(point.x(), point.y()));
        int x = m_rect.left() + mapped.x();
        int y = m_rect.top() + mapped.y();

        contact.pointerInfo.pointerType = PT_TOUCH;
        contact.pointerInfo.pointerId = point.id();
        contact.pointerInfo.ptPixelLocation.x = x;
        contact.pointerInfo.ptPixelLocation.y = y;

        QTouchPointState ps = point.state();
        if (ps & Qt::TouchPointPressed) {
            contact.pointerInfo.pointerFlags = POINTER_FLAG_DOWN | POINTER_FLAG_INCONTACT | POINTER_FLAG_INRANGE;
        } else if (ps & Qt::TouchPointReleased) {
            contact.pointerInfo.pointerFlags = POINTER_FLAG_UP;
        } else if (ps & Qt::TouchPointMoved) {
            contact.pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INCONTACT | POINTER_FLAG_INRANGE;
        } else if (ps & Qt::TouchPointStationary) {
            contact.pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INCONTACT | POINTER_FLAG_INRANGE;
        }

        contact.touchFlags = TOUCH_FLAG_NONE;
        contact.touchMask = TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE;

        contact.rcContact.left   = x - 2;
        contact.rcContact.top    = y - 2;
        contact.rcContact.right  = x + 2;
        contact.rcContact.bottom = y + 2;

        contact.orientation = 90;
        contact.pressure    = 512;

        touchList.push_back(contact);
    }

    if (!_InjectTouchInput(static_cast<UINT>(touchList.size()), touchList.data())) {
        // qWarning("InjectTouchInput failed!");
    }
}

void TouchInjector::handleMouse(const QList<TouchPoint> &points)
{
    if (points.isEmpty()) return;

    int numActive = 0;
    QPoint pos;

    for (const TouchPoint &p : points) {
        if (!p.isValid()) continue;
        numActive++;
        pos = QPoint(m_rect.left() + p.x(), m_rect.top() + p.y());
    }

    if (numActive == 1) {
        // 单指
        SetCursorPos(pos.x(), pos.y());

        const TouchPoint &p = points[0];
        static QElapsedTimer clickTimer;
        static bool firstClick = true;

        if (p.state() & Qt::TouchPointPressed) {
            if (!firstClick && clickTimer.elapsed() < 400) { // 双击阈值 ms
                // 单指双击 -> 左键点击一次
                mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, pos.x(), pos.y(), 0, 0);
                firstClick = true; // 重置
            } else {
                clickTimer.restart();
                firstClick = false;
            }
        } else if (p.state() & Qt::TouchPointMoved) {
            // 鼠标移动已经通过 SetCursorPos 完成
        }

    } else if (numActive >= 2) {
        // 双指点击 -> 右键点击一次
        mouse_event(MOUSEEVENTF_RIGHTDOWN | MOUSEEVENTF_RIGHTUP, pos.x(), pos.y(), 0, 0);
    }
}

